package com.fsserver.web.controller;

import com.fsserver.common.api.ApiResponse;
import com.fsserver.common.utils.MDCTraceUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.info.BuildProperties;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.sql.DataSource;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.RuntimeMXBean;
import java.sql.Connection;
import java.sql.SQLException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 健康检查控制器
 * 提供系统健康状态检查接口
 * 
 * @author fsserver
 * @date 2023-03-13
 */
@RestController
@RequestMapping("/health")
public class HealthCheckController {
    private static final Logger log = LoggerFactory.getLogger(HealthCheckController.class);
    
    @Autowired
    private Environment environment;
    
    @Autowired
    private DataSource dataSource;
    
    @Autowired(required = false)
    private BuildProperties buildProperties;
    
    /**
     * 简单健康检查
     * 用于负载均衡器检查服务是否在线
     * 
     * @return 健康状态
     */
    @GetMapping("/ping")
    public String ping() {
        return "pong";
    }
    
    /**
     * 详细健康检查
     * 提供系统详细健康状态信息
     * 
     * @return 健康状态详情
     */
    @GetMapping("/status")
    public ApiResponse<Map<String, Object>> status() {
        String traceId = MDCTraceUtils.getTraceId();
        log.info("执行健康检查 [traceId: {}]", traceId);
        
        Map<String, Object> status = new HashMap<>();
        Map<String, Object> systemInfo = new HashMap<>();
        Map<String, Object> memoryInfo = new HashMap<>();
        Map<String, Object> applicationInfo = new HashMap<>();
        Map<String, Object> databaseInfo = new HashMap<>();
        
        // 系统信息
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        systemInfo.put("javaVersion", System.getProperty("java.version"));
        systemInfo.put("javaVendor", System.getProperty("java.vendor"));
        systemInfo.put("osName", System.getProperty("os.name"));
        systemInfo.put("osVersion", System.getProperty("os.version"));
        systemInfo.put("osArch", System.getProperty("os.arch"));
        systemInfo.put("processors", Runtime.getRuntime().availableProcessors());
        
        // 运行时信息
        long uptime = runtimeMXBean.getUptime();
        long uptimeInSeconds = TimeUnit.MILLISECONDS.toSeconds(uptime);
        long days = uptimeInSeconds / (24 * 3600);
        long hours = (uptimeInSeconds % (24 * 3600)) / 3600;
        long minutes = (uptimeInSeconds % 3600) / 60;
        long seconds = uptimeInSeconds % 60;
        
        systemInfo.put("uptime", String.format("%d天%d小时%d分钟%d秒", days, hours, minutes, seconds));
        systemInfo.put("startTime", formatInstant(Instant.ofEpochMilli(runtimeMXBean.getStartTime())));
        systemInfo.put("currentTime", formatInstant(Instant.now()));
        
        // 内存信息
        MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
        long heapUsed = memoryMXBean.getHeapMemoryUsage().getUsed();
        long heapMax = memoryMXBean.getHeapMemoryUsage().getMax();
        long nonHeapUsed = memoryMXBean.getNonHeapMemoryUsage().getUsed();
        
        memoryInfo.put("heapUsed", formatSize(heapUsed));
        memoryInfo.put("heapMax", formatSize(heapMax));
        memoryInfo.put("heapUtilization", String.format("%.2f%%", (double) heapUsed / heapMax * 100));
        memoryInfo.put("nonHeapUsed", formatSize(nonHeapUsed));
        
        // 应用信息
        applicationInfo.put("profiles", environment.getActiveProfiles());
        applicationInfo.put("serverPort", environment.getProperty("server.port"));
        applicationInfo.put("contextPath", environment.getProperty("server.servlet.context-path", ""));
        
        if (buildProperties != null) {
            applicationInfo.put("name", buildProperties.getName());
            applicationInfo.put("version", buildProperties.getVersion());
            applicationInfo.put("buildTime", buildProperties.getTime());
        }
        
        // 数据库连接检查
        boolean dbConnected = checkDatabaseConnection();
        databaseInfo.put("connected", dbConnected);
        databaseInfo.put("url", maskDatabaseUrl(environment.getProperty("spring.datasource.url")));
        
        // 组装状态信息
        status.put("status", dbConnected ? "UP" : "DOWN");
        status.put("system", systemInfo);
        status.put("memory", memoryInfo);
        status.put("application", applicationInfo);
        status.put("database", databaseInfo);
        status.put("timestamp", System.currentTimeMillis());
        status.put("traceId", traceId);
        
        return ApiResponse.success(status);
    }
    
    /**
     * 检查数据库连接
     * 
     * @return 连接是否正常
     */
    private boolean checkDatabaseConnection() {
        try (Connection connection = dataSource.getConnection()) {
            return connection.isValid(3);
        } catch (SQLException e) {
            log.error("数据库连接检查失败", e);
            return false;
        }
    }
    
    /**
     * 格式化时间戳
     * 
     * @param instant 时间戳
     * @return 格式化后的时间字符串
     */
    private String formatInstant(Instant instant) {
        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault())
                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }
    
    /**
     * 格式化字节大小
     * 
     * @param bytes 字节数
     * @return 格式化后的大小字符串
     */
    private String formatSize(long bytes) {
        if (bytes < 1024) {
            return bytes + " B";
        } else if (bytes < 1024 * 1024) {
            return String.format("%.2f KB", bytes / 1024.0);
        } else if (bytes < 1024 * 1024 * 1024) {
            return String.format("%.2f MB", bytes / (1024.0 * 1024));
        } else {
            return String.format("%.2f GB", bytes / (1024.0 * 1024 * 1024));
        }
    }
    
    /**
     * 掩盖数据库URL中的敏感信息
     * 
     * @param url 数据库URL
     * @return 掩盖敏感信息后的URL
     */
    private String maskDatabaseUrl(String url) {
        if (url == null) {
            return null;
        }
        
        // 掩盖可能的用户名和密码
        return url.replaceAll("://([^:]+):([^@]+)@", "://*****:*****@");
    }
} 